package com.bbc.base;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

public class BaseUrl {
	
	public static void main(String[] args) {
		BaseUrl bu = new BaseUrl();
		bu.setUrl("http://localhost:8080/bbc");
		System.out.println(bu.getUrl());
		bu.getTarget("/main/t.action");
		bu.addQueryData("a", 1);
		bu.addQueryData("c", 3);
		System.out.println(bu);
		System.out.println(bu);

	}
	
	private String username;
    private String password;
    private String protocol;
    private String host;
    private int port;
    private String path;
    private String contextPath;
    private boolean reset;
    private boolean filter;
    private Map<String, Object> query;
    private BaseUrl baseUrl;
    private String charsetName;
    private String url;
	
	public BaseUrl()
    {
        protocol = "http";
        port = -1;
        filter = true;
        query = new LinkedHashMap<String, Object>();
        charsetName = "utf-8";
    }

    public String getUsername()
    {
        return username;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public String getPassword()
    {
        return password;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public String getProtocol()
    {
        return protocol;
    }

    public void setProtocol(String protocol)
    {
        this.protocol = protocol;
    }

    public String getHost()
    {
        return host;
    }

    public void setHost(String host)
    {
        this.host = host;
    }

    public int getPort()
    {
        return port;
    }

    public void setPort(int port)
    {
        this.port = port;
    }

    public String getPath()
    {
        return path;
    }

    public void setPath(String path)
    {
        this.path = path;
    }

    public BaseUrl addQueryData(String name, String value)
    {
        query.put(name, value);
        return this;
    }

    public BaseUrl addQueryData(String name, Object value)
    {
        query.put(name, value);
        return this;
    }

    public BaseUrl addQueryData(String name, int value)
    {
        query.put(name, Integer.valueOf(value));
        return this;
    }

    public BaseUrl addQueryData(String name, long value)
    {
        query.put(name, Long.valueOf(value));
        return this;
    }

    public BaseUrl addQueryData(String name, float value)
    {
        query.put(name, Float.valueOf(value));
        return this;
    }

    public BaseUrl getTarget(String target)
    {
        path = target;
        return this;
    }
    
    public BaseUrl getTargetByPID(Integer id)
    {
        path = "/"+id+".html";
        return this;
    }

    public String render()
    {
        String s;
        s = doIt();
        return s;
    }

    private String doIt()
    {
        String str;
        try
        {
            String path = prefixPath(contextPath, this.path);
            URL url = new URL(protocol, host, port, path);
            if(url.getDefaultPort() == url.getPort())
                url = new URL(protocol, host, -1, path);
            str = url.toString();
        }
        catch(Exception e)
        {
            str = "/";
        }
        StringBuilder builder = new StringBuilder(str);
        if(!query.isEmpty())
        {
            for(Iterator<String> i$ = query.keySet().iterator(); i$.hasNext();)
            {
                String key = (String)i$.next();
                Object obj = query.get(key);
                if(obj instanceof List)
                {
                    @SuppressWarnings("unchecked")
					List<Object> list = (List<Object>)obj;
                    Iterator<Object> ii = list.iterator();
                    while(ii.hasNext()) 
                    {
                        Object o = ii.next();
                        setValue(builder, key, o);
                    }
                } else
                if(obj instanceof Map)
                {
                    @SuppressWarnings("unchecked")
					Map<String, Object> map = (Map<String, Object>)obj;
                    Iterator<String> it = map.keySet().iterator();
                    while(i$.hasNext()) 
                    {
                        Object o = it.next();
                        setValue(builder, o != null ? o.toString() : "", map.get(o));
                    }
                } else
                if(obj != null && obj.getClass().isArray())
                {
                    Object arrays[] = (Object[])(Object[])obj;
                    Object arr$[] = arrays;
                    int len$ = arr$.length;
                    int i = 0;
                    while(i < len$) 
                    {
                        Object o = arr$[i];
                        setValue(builder, key, o);
                        i++;
                    }
                } else
                {
                    setValue(builder, key, obj);
                }
            }

            return builder.replace(str.length(), str.length() + 1, "?").toString();
        } else
        {
            return str;
        }
    }

    public String prefixPath(String contextPath, String path)
    {
        String returnPath;
        if(path == null || contextPath == null)
        {
            if(path == null && contextPath == null)
                returnPath = "/";
            else
            if(contextPath == null)
                returnPath = path;
            else
                returnPath = contextPath;
        } else
        if(contextPath.endsWith("/") && path.startsWith("/"))
            returnPath = (new StringBuilder()).append(contextPath).append(path.substring(1)).toString();
        else
            returnPath = (new StringBuilder()).append(contextPath).append(path).toString();
        return returnPath;
    }

    public void setValue(StringBuilder builder, String key, Object o)
    {
        String value = o != null ? o.toString() : "";
        if(value.length() > 0)
        {
            String str1 = encodeUrl(value);
            builder.append("&").append(key).append("=").append(str1);
        } else
        if(!filter)
            builder.append("&").append(key).append("=");
    }

    @SuppressWarnings("deprecation")
	public String encodeUrl(String value)
    {
        String str1;
        if(StringUtils.isNotBlank(charsetName))
            try
            {
                str1 = URLEncoder.encode(value, charsetName);
            }
            catch(UnsupportedEncodingException e)
            {
                str1 = value;
            }
        else
            str1 = URLEncoder.encode(value);
        return str1;
    }

    public String toString()
    {
        String s = render();
        if(!reset)
        {
            reset = true;
            reset();
        }
        reset = false;
        return s;
    }

    public void reset()
    {
        try
        {
            reset = true;
            query.clear();
            baseUrl = new BaseUrl();
            baseUrl.setUrl(url);
			query.putAll(baseUrl.query);
            baseUrl.setBaseUrlValue(this, baseUrl);
        }
        catch(Exception e)
        {
        	e.printStackTrace();
        }
    }

    public void setUrl(String url) {
    	this.url = url;
        URL a;
		try {
			a = new URL(url);
			protocol = a.getProtocol();
	        host = a.getHost();
	        port = a.getPort();
	        contextPath = a.getPath();
	        String queryString = a.getQuery();
	        if(!StringUtils.isEmpty(queryString))
	            query.putAll(getQueryMap(queryString));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
    }

    private Map<String, Object> getQueryMap(String query)
    {
        String params[] = query.split("&");
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        String arr$[] = params;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            String param = arr$[i$];
            String strings[] = param.split("=");
            String name = strings[0];
            String value = null;
            if(strings.length > 1)
                value = strings[1];
            map.put(name, value);
        }

        return map;
    }
    
    private void setBaseUrlValue(BaseUrl dest, BaseUrl src)
    {
        dest.username = src.username;
        dest.password = src.password;
        dest.protocol = src.protocol;
        dest.host = src.host;
        dest.port = src.port;
        dest.contextPath = src.contextPath;
        dest.path = src.path;
    }

    public void cleanQueryMap()
    {
        if(query != null && !query.isEmpty())
            query.clear();
    }

    public void setCharsetName(String charsetName)
    {
        this.charsetName = charsetName;
    }

    public String getCharsetName()
    {
        return charsetName;
    }

    public boolean isFilter()
    {
        return filter;
    }

    public void setFilter(boolean filter)
    {
        this.filter = filter;
    }

    public String getContextPath()
    {
        return contextPath;
    }

    public void setContextPath(String contextPath)
    {
        this.contextPath = contextPath;
    }

    public void setQuery(Map<String, Object> query){
        this.query = query;
    }

    public Map<String, Object> getQuery()
    {
        return query;
    }
    public BaseUrl getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(BaseUrl baseUrl) {
		this.baseUrl = baseUrl;
	}

	public String getUrl() {
		return url;
	}

}
